﻿#include <stdio.h>
#include <iostream>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "meter.h"
#include "libutils.h"
#include "dlt645.h"	// support DL/T 645-1997

// 当前正向有功总电能
// DI1=1001 00 00 | DI0=0001 0000
// 电能量 当前 有功 | 正向电能 总电能
int meter::get_zong(void)
{
	zong = gu + ping + feng;
	return zong;
}

int meter::get_gu(void)
{
	return gu;
}

int meter::get_ping(void)
{	
	return ping;
}

int meter::get_feng(void)
{
	return feng;
}

void meter::set_zong(void)
{
	;
}

void meter::set_gu(int g)
{
	gu = g;
}

void meter::set_ping(int p)
{
	ping = p;
}

void meter::set_feng(int f)
{
	feng = f;
}

/* MAC */
void meter::set_mac(char *buf)
{
	strcpy(MAC, buf);
}

char *meter::get_mac(void)
{
	char *p = MAC;
	return p;
}

/* set and get time */
void meter::set_time(time_t t)
{
	ltime = t;
}

time_t meter::get_time(void)
{
	return ltime;
}

/* init function */
void meter::init(void)
{
	char macstr[13];
	strcpy(macstr, "000090620012");

	set_feng(0);
	set_gu(0);
	set_ping(0);
	set_mac(macstr);

#if 0
	m_info[0].di1 = 0x90;
	m_info[0].di0 = 0x10;
	sprintf((char *)m_info[0].data, "%f", get_gu());
#endif

	/* current time */
	set_time(time(NULL));
}

meter m;
void *serv_proc(void *arg);

/* update every five minutes */
void meter::run(void)
{
	int zong, gu, ping;
	pthread_t tid;
	char *pstr = (char*)tx_buf;

	printf("-----运行-----\n");
	printf("MAC: %s\n", get_mac());
	printf("时间: %s\n", ctime(&ltime));
	pthread_create(&tid, NULL, serv_proc, NULL);	
	
	while(1) {
		ltime++;
		feng = get_feng();
		gu = get_gu();
		ping = get_ping();
		zong = get_zong();
		
		sprintf(pstr, "总: %8d 谷: %8d 平: %8d 峰: %8d",
			zong, gu, ping, feng);

		//fflush(stdout);
		#if 1
		printf("MAC: %s\n", get_mac());
		printf("时间: %s", ctime(&ltime));
		printf("%s\n\n", pstr);
		#endif
	
		set_gu(gu + get_random());
		set_ping(ping + get_random());
		set_feng(feng + get_random());
		
		sleep(3);
	}

	free(pstr);
}


/*
电表模拟实现：
1. 读数据
	可对"主站请求帧"响应，返回"从站正常应答"或"异常应答"
	请 求 帧：C=01H L=02H DI0DI1
	正常应答：C=81H/A1H(无/有后续帧) L=02H+M DI0DI1 DATA 
	异常应答：C=C1H L=01H ERR_CODE
 2. 读后续数据
	可对"主站请求后续帧"响应，返回“从站正常应答”或“异常应答”
	请 求 帧：C=02H L=02H
	正常应答：C=82H/A2H（无/有后续帧） L=02H+M DI0DI1 DATA
	异常应答：C=C2H L=01H ERR_CODE
3. 重读数据	TODO
4. 写数据
	可对“主站设置数据请求”响应，返回从站“正常”或“异常”应答
	请 求 帧：C=04H L=02H DI0DI1
	正常应答：C=84H L=00H
	异常应答：C=C4H L=01H err_code
5. 广播校时
	可对“主站广播校时请求”响应，不要求应答
	请 求 帧：C=08H L=06H DATA=YYMMDDHHMMSS
*/

void *serv_proc(void *arg)
{
	struct sockaddr_in servaddr, cliaddr;
	socklen_t addrlen;
	int sockid;

	sockid = socket(AF_INET, SOCK_DGRAM, 0);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(2345);
	
	if (bind(sockid, (struct sockaddr *)&servaddr, 
		sizeof(servaddr)) != 0) {
		printf("Can't bind.\n");
		exit(1);
	}
	bzero(&cliaddr, sizeof(cliaddr));

	while(1) {
		int recvlen;
		dlt645 *p;

		cliaddr.sin_family = AF_INET;
		addrlen = sizeof(cliaddr);
		recvlen = recvfrom(sockid, m.rx_buf, BUFSIZ,0,
			(struct sockaddr *)&cliaddr, &addrlen);

		if(dlt645_valid_check(m.rx_buf, recvlen) == 0)
			printf("合法数据报\n");
		else {
			printf("非法数据报\n");
			continue;
		}

		p = (dlt645*)(m.rx_buf);

		if(dlt645_response(p, recvlen, &m, NULL) == 1) {
			printf("%s\n", (char*)m.tx_buf);
			printf("发送中...\n");
			sendto(sockid, m.tx_buf, sizeof(m.tx_buf), 0, 
				(struct sockaddr*)&cliaddr, sizeof(cliaddr));
		}

		#if 0
		if(strncmp(m.rx_buf, "init", 4) == 0)
			m.init();
		sendto(sockid, m.tx_buf, strlen(m.tx_buf), 0, 
			(struct sockaddr*)&cliaddr, sizeof(cliaddr));	
		#endif
		
	}
}

using namespace std;

int main(int argc, char **argv)
{
	m.init();
	m.run();

	return 0;
}

